/** * JBoss, Home of Professional Open Source * * Copyright 2011, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.seam.validation; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.event.Observes; import javax.enterprise.inject.Any; import javax.enterprise.inject.Default; import javax.enterprise.inject.spi.AfterBeanDiscovery; import javax.enterprise.inject.spi.AnnotatedType; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.InjectionPoint; import javax.enterprise.inject.spi.InjectionTarget; import javax.enterprise.util.AnnotationLiteral; import javax.validation.ConstraintValidatorFactory; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; import org.hibernate.validator.MethodValidator; /** * A CDI portable extension which registers beans for {@link ValidatorFactory} * and {@link Validator}, if such beans not yet exist (which for instance would * be the case in a Java EE 6 container). Furthermore a {@link MethodValidator} * bean is registered. All registered beans will be {@link ApplicationScoped}. * * @author Gunnar Morling * */ public class ValidationExtension implements Extension { public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { addValidatorFactoryIfRequired(abd, bm); addValidatorIfRequired(abd, bm); addMethodValidator(abd, bm); } private void addValidatorFactoryIfRequired(AfterBeanDiscovery abd, final BeanManager beanManager) { // if a ValidatorFactory already exists, only inject it's ConstraintValidatorFactory if required if (!beanManager.getBeans(ValidatorFactory.class).isEmpty()) { ValidatorFactory validatorFactory = getReference(beanManager, ValidatorFactory.class); ConstraintValidatorFactory constraintValidatorFactory = validatorFactory.getConstraintValidatorFactory(); if(constraintValidatorFactory instanceof InjectingConstraintValidatorFactory) { inject(beanManager, InjectingConstraintValidatorFactory.class, (InjectingConstraintValidatorFactory)constraintValidatorFactory); } return; } abd.addBean(new Bean<ValidatorFactory>() { @Override public Class<?> getBeanClass() { return ValidatorFactory.class; } @Override public Set<InjectionPoint> getInjectionPoints() { return Collections.emptySet(); } @Override public String getName() { return "validatorFactory"; } @SuppressWarnings("serial") @Override public Set<Annotation> getQualifiers() { Set<Annotation> qualifiers = new HashSet<Annotation>(); qualifiers.add(new AnnotationLiteral<Default>() { }); qualifiers.add(new AnnotationLiteral<Any>() { }); return qualifiers; } @Override public Class<? extends Annotation> getScope() { return ApplicationScoped.class; } @Override public Set<Class<? extends Annotation>> getStereotypes() { return Collections.emptySet(); } @Override public Set<Type> getTypes() { Set<Type> types = new HashSet<Type>(); types.add(ValidatorFactory.class); types.add(Object.class); return types; } @Override public boolean isAlternative() { return false; } @Override public boolean isNullable() { return false; } @Override public ValidatorFactory create(CreationalContext<ValidatorFactory> ctx) { ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); ConstraintValidatorFactory constraintValidatorFactory = validatorFactory.getConstraintValidatorFactory(); if(constraintValidatorFactory instanceof InjectingConstraintValidatorFactory) { inject(beanManager, InjectingConstraintValidatorFactory.class, (InjectingConstraintValidatorFactory)constraintValidatorFactory); } return validatorFactory; } @Override public void destroy(ValidatorFactory instance, CreationalContext<ValidatorFactory> ctx) { } }); } private void addValidatorIfRequired(AfterBeanDiscovery abd, final BeanManager bm) { // do nothing, if Validator already exists if (!bm.getBeans(Validator.class).isEmpty()) { return; } abd.addBean(new Bean<Validator>() { @Override public Class<?> getBeanClass() { return Validator.class; } @Override public Set<InjectionPoint> getInjectionPoints() { return Collections.emptySet(); } @Override public String getName() { return "validator"; } @SuppressWarnings("serial") @Override public Set<Annotation> getQualifiers() { Set<Annotation> qualifiers = new HashSet<Annotation>(); qualifiers.add(new AnnotationLiteral<Default>() { }); qualifiers.add(new AnnotationLiteral<Any>() { }); return qualifiers; } @Override public Class<? extends Annotation> getScope() { return ApplicationScoped.class; } @Override public Set<Class<? extends Annotation>> getStereotypes() { return Collections.emptySet(); } @Override public Set<Type> getTypes() { Set<Type> types = new HashSet<Type>(); types.add(MethodValidator.class); types.add(Validator.class); types.add(Object.class); return types; } @Override public boolean isAlternative() { return false; } @Override public boolean isNullable() { return false; } @Override public Validator create(CreationalContext<Validator> ctx) { ValidatorFactory validatorFactory = getReference(bm, ValidatorFactory.class); return validatorFactory.getValidator(); } @Override public void destroy(Validator instance, CreationalContext<Validator> ctx) { } }); } private void addMethodValidator(AfterBeanDiscovery abd, final BeanManager bm) { abd.addBean(new Bean<MethodValidator>() { @Override public Class<?> getBeanClass() { return MethodValidator.class; } @Override public Set<InjectionPoint> getInjectionPoints() { return Collections.emptySet(); } @Override public String getName() { return "methodValidator"; } @SuppressWarnings("serial") @Override public Set<Annotation> getQualifiers() { Set<Annotation> qualifiers = new HashSet<Annotation>(); qualifiers.add(new AnnotationLiteral<Default>() { }); qualifiers.add(new AnnotationLiteral<Any>() { }); return qualifiers; } @Override public Class<? extends Annotation> getScope() { return ApplicationScoped.class; } @Override public Set<Class<? extends Annotation>> getStereotypes() { return Collections.emptySet(); } @Override public Set<Type> getTypes() { Set<Type> types = new HashSet<Type>(); types.add(MethodValidator.class); types.add(Object.class); return types; } @Override public boolean isAlternative() { return false; } @Override public boolean isNullable() { return false; } @Override public MethodValidator create(CreationalContext<MethodValidator> ctx) { return getReference(bm, ValidatorFactory.class).getValidator().unwrap(MethodValidator.class); } @Override public void destroy(MethodValidator instance, CreationalContext<MethodValidator> ctx) { } }); } @SuppressWarnings("unchecked") private <T> T getReference(BeanManager bm, Class<T> clazz) { Bean<T> bean = (Bean<T>) bm.getBeans(clazz).iterator().next(); CreationalContext<T> context = bm.createCreationalContext(bean); return (T) bm.getReference(bean, clazz, context); } private <T> void inject(final BeanManager beanManager, Class<T> type, T constraintValidatorFactory) { AnnotatedType<T> annotatedType = beanManager.createAnnotatedType(type); InjectionTarget<T> it = beanManager.createInjectionTarget(annotatedType); CreationalContext<T> cvfCtx = beanManager.createCreationalContext(null); it.inject(constraintValidatorFactory, cvfCtx); it.postConstruct(constraintValidatorFactory); } }